package modele;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Classe gérant les connexions avec la base de données
 * et les opérations standards
 * @author Théo
 */
public class Database {
    private static Database instance;
    public static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
    public static final String URL_TEMPLATE = "jdbc:mysql://localhost/";
    public static String db;
    public static String url;
    public static String user;
    public static String password;
    public static final String OUTPUT_DATA_SET_FILENAME = "dataSets/outputFlatXmlDataSetClean.xml";
    public static final String INPUT_DATA_SET_FILENAME = "dataSets/inputFlatXmlDataSetClean.xml";

    private Database() {
        try {
            // Chargement du pilote
            Class.forName(DRIVER_NAME).newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Sets the connection data needed to connect to the database
     * @param db The database's name
     * @param user The user's login
     * @param password The user's password
     */
    public static void setConnectionData(String db, String user, String password) {
        Database.db = db;
        Database.user = user;
        Database.password = password;
        Database.url = URL_TEMPLATE + db;
    }

    /**
     * Méthode du design pattern du singleton
     * Renvoie l'instance de la classe, et initialise le driver
     * si cela n'a pas encore été fait
     * @return L'instance de la classe Database
     */
    public static Database getInstance() {
        // Si le singleton n'a pas encore été initialisé (== pilote initialisé),
        // alors le faire via le constructeur
        if ((instance == null)) {
            instance = new Database();
        }
        return instance;
    }

    /**
     * Retourne une connexion à la base de données
     */
    public Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(url, user, password);
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
        return conn;
    }

    /**
     * Ferme une connexion
     */
    public void close(final Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException ex) {
                Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Ferme un Statement
     */
    public void close(final Statement stat) {
        if (stat != null) {
            try {
                stat.close();
            } catch (SQLException ex) {
                Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Ferme un ResultSet
     */
    public void close(final ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ex) {
                Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Effectue une requête standard de sélection
     * @param table La table sur laquelle effectuer la sélection
     * @param field Le champ sur lequel effectuer la contrainte
     * @param value La valeur que le champ doit vérifier
     * @return La sélection sur la table
     */
    public ResultSet getTableByField(String table, String field, String value) {
        Connection connexion = Database.getInstance().getConnection();
        ResultSet rs = null;

        try {
            String sql = "SELECT * FROM " + table
                    + " WHERE " + field + " = " + "\'" + value + "\'";
            Statement stmt = connexion.createStatement();
            System.out.println(sql);
            System.out.println("Statement instancié");
            rs = stmt.executeQuery(sql);
            System.out.println("SQL executé");
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Database.getInstance().close(connexion);
        }

        return rs;
    }

    /**
     * Effectue une requête standard de sélection
     * @param table La table sur laquelle effectuer la sélection
     * @param field Le champ sur lequel effectuer la contrainte
     * @param value La valeur que le champ doit vérifier
     * @return La sélection sur la table
     */
    public ResultSet getTableByField(String table, String field, int value) {
        Connection connexion = Database.getInstance().getConnection();
        ResultSet rs = null;

        try {
            String sql = "SELECT * FROM " + table
                    + " WHERE " + field + " = " + value;
            System.out.println(sql);
            Statement stmt = connexion.createStatement();
            System.out.println("Statement instancié");
            rs = stmt.executeQuery(sql);
            System.out.println("SQL executé");
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            Database.getInstance().close(connexion);
        }

        return rs;
    }

    /**
     * Exécute la query donnée en paramètre sur la base
     * @param sql La query à exécuter
     * @return Le ResultSet réponse
     */
    public ResultSet read(String sql) {
        Statement stRead;
        try {
            stRead = (Statement) Database.getInstance().getConnection().createStatement();
            ResultSet set = stRead.executeQuery(sql);
            return set;
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * Réinitialise la base de données
     */
    public void reset() {
        /*
        try {
        Statement stWrite;
        stWrite = (Statement) Bdd.getInstance().getConnection().createStatement();
        String sql = "CREATE TABLE `analyse` (  `nom` varchar(10) NOT NULL,  `commentaire` varchar(255) NOT NULL,  PRIMARY KEY  (`nom`))";
        stWrite.executeUpdate(sql);
        } catch (SQLException ex) {
        Logger.getLogger(Bdd.class.getName()).log(Level.SEVERE, null, ex);
        }
         */
    }

    /**
     * Exécute l'ordre donné en paramètre sur la base
     * @param sql L'ordre à exécuter
     */
    public void write(String sql) {
        Statement stWrite;
        try {
            System.out.println(sql);
            stWrite = (Statement) Database.getInstance().getConnection().createStatement();
            stWrite.executeUpdate(sql);
        } catch (SQLException ex) {
            Logger.getLogger(Database.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static String getDb() {
        return db;
    }
}
